use wasm_bindgen::prelude::*;
use image::{DynamicImage, ImageFormat, ImageOutputFormat, GenericImageView};
use fast_image_resize as fir;
use std::io::Cursor;

// WebAssembly 初始化代码

#[wasm_bindgen]
extern "C" {
    fn alert(s: &str);
    
    #[wasm_bindgen(js_namespace = console)]
    fn log(s: &str);
}

macro_rules! console_log {
    ($($t:tt)*) => (log(&format_args!($($t)*).to_string()))
}

/// 图片尺寸信息
#[wasm_bindgen]
#[derive(Debug, Clone)]
pub struct ImageDimensions {
    width: u32,
    height: u32,
}

#[wasm_bindgen]
impl ImageDimensions {
    #[wasm_bindgen(getter)]
    pub fn width(&self) -> u32 {
        self.width
    }

    #[wasm_bindgen(getter)]
    pub fn height(&self) -> u32 {
        self.height
    }
}

/// 缩放结果
#[wasm_bindgen]
#[derive(Debug, Clone)]
pub struct ResizeResult {
    data: Vec<u8>,
    width: u32,
    height: u32,
    format: String,
}

#[wasm_bindgen]
impl ResizeResult {
    #[wasm_bindgen(getter)]
    pub fn data(&self) -> js_sys::Uint8Array {
        js_sys::Uint8Array::from(&self.data[..])
    }

    #[wasm_bindgen(getter)]
    pub fn width(&self) -> u32 {
        self.width
    }

    #[wasm_bindgen(getter)]
    pub fn height(&self) -> u32 {
        self.height
    }

    #[wasm_bindgen(getter)]
    pub fn format(&self) -> String {
        self.format.clone()
    }
}

/// 检测图片格式
fn detect_format(data: &[u8]) -> Result<ImageFormat, String> {
    image::guess_format(data).map_err(|e| format!("无法检测图片格式: {}", e))
}

/// 解码图片并返回格式信息
fn decode_image_with_format(data: &[u8]) -> Result<(DynamicImage, ImageFormat), String> {
    let format = detect_format(data)?;
    let img = image::load_from_memory_with_format(data, format)
        .map_err(|e| format!("图片解码失败: {}", e))?;
    Ok((img, format))
}

/// 编码图片
fn encode_image(img: &DynamicImage, format: ImageFormat) -> Result<Vec<u8>, String> {
    let mut buffer = Vec::new();
    let mut cursor = Cursor::new(&mut buffer);
    
    let output_format = match format {
        ImageFormat::Jpeg => ImageOutputFormat::Jpeg(85),
        ImageFormat::Png => ImageOutputFormat::Png,
        ImageFormat::Gif => ImageOutputFormat::Gif,
        ImageFormat::WebP => ImageOutputFormat::WebP,
        ImageFormat::Bmp => ImageOutputFormat::Bmp,
        ImageFormat::Tiff => ImageOutputFormat::Tiff,
        _ => return Err(format!("不支持的输出格式: {:?}", format)),
    };
    
    img.write_to(&mut cursor, output_format)
        .map_err(|e| format!("图片编码失败: {}", e))?;
    
    Ok(buffer)
}

/// 将字符串转换为 fast_image_resize 的算法类型
fn parse_resize_algorithm(filter: &str) -> Result<fir::ResizeAlg, String> {
    match filter.to_lowercase().as_str() {
        "nearest" => Ok(fir::ResizeAlg::Nearest),
        "bilinear" | "triangle" => Ok(fir::ResizeAlg::Convolution(fir::FilterType::Bilinear)),
        "catmullrom" => Ok(fir::ResizeAlg::Convolution(fir::FilterType::CatmullRom)),
        "lanczos3" | "gaussian" => Ok(fir::ResizeAlg::Convolution(fir::FilterType::Lanczos3)),
        _ => Err(format!("不支持的缩放算法: {}", filter)),
    }
}

/// 使用 fast_image_resize 进行高性能缩放
fn resize_with_fast_image_resize(
    img: &DynamicImage,
    new_width: u32,
    new_height: u32,
    algorithm: fir::ResizeAlg,
) -> Result<DynamicImage, String> {
    // 转换为 RGBA8 格式进行处理
    let rgba_img = img.to_rgba8();
    let (width, height) = rgba_img.dimensions();
    
    // 创建源图像
    let src_image = fir::Image::from_vec_u8(
        std::num::NonZeroU32::new(width).unwrap(),
        std::num::NonZeroU32::new(height).unwrap(),
        rgba_img.into_raw(),
        fir::PixelType::U8x4,
    ).map_err(|e| format!("创建源图像失败: {}", e))?;
    
    // 创建目标图像
    let mut dst_image = fir::Image::new(
        std::num::NonZeroU32::new(new_width).unwrap(),
        std::num::NonZeroU32::new(new_height).unwrap(),
        fir::PixelType::U8x4,
    );
    
    // 创建缩放器
    let mut resizer = fir::Resizer::new(algorithm);
    
    // 执行缩放
    resizer.resize(&src_image.view(), &mut dst_image.view_mut())
        .map_err(|e| format!("图像缩放失败: {}", e))?;
    
    // 转换回 DynamicImage
    let buffer = dst_image.into_vec();
    let rgba_buffer = image::RgbaImage::from_raw(new_width, new_height, buffer)
        .ok_or("无法创建 RGBA 图像缓冲区")?;
    
    Ok(DynamicImage::ImageRgba8(rgba_buffer))
}

/// 固定尺寸缩放
#[wasm_bindgen]
pub fn resize_image(
    image_data: &[u8],
    width: u32,
    height: u32,
    filter: &str,
) -> Result<ResizeResult, String> {
    console_log!("开始缩放图片到固定尺寸: {}x{}, 算法: {}", width, height, filter);
    
    let (img, format) = decode_image_with_format(image_data)?;
    let algorithm = parse_resize_algorithm(filter)?;
    
    let resized_img = resize_with_fast_image_resize(&img, width, height, algorithm)?;
    let output_data = encode_image(&resized_img, format)?;
    
    console_log!("图片缩放完成，输出大小: {} bytes", output_data.len());
    
    Ok(ResizeResult {
        data: output_data,
        width,
        height,
        format: format!("{:?}", format).to_lowercase(),
    })
}

/// 等比例缩放（支持单边限制）
#[wasm_bindgen]
pub fn resize_image_aspect_ratio(
    image_data: &[u8],
    max_width: u32,
    max_height: u32,
    filter: &str,
) -> Result<ResizeResult, String> {
    console_log!("开始等比例缩放: max_width={}, max_height={}, 算法: {}", max_width, max_height, filter);
    
    let (img, format) = decode_image_with_format(image_data)?;
    let (orig_width, orig_height) = img.dimensions();
    
    console_log!("原始尺寸: {}x{}", orig_width, orig_height);
    
    // 计算目标尺寸
    let (new_width, new_height) = match (max_width, max_height) {
        (0, 0) => {
            // 都不限制，返回原图
            console_log!("无尺寸限制，返回原图");
            let output_data = encode_image(&img, format)?;
            return Ok(ResizeResult {
                data: output_data,
                width: orig_width,
                height: orig_height,
                format: format!("{:?}", format).to_lowercase(),
            });
        }
        (0, max_h) => {
            // 只限制高度
            if orig_height <= max_h {
                console_log!("高度未超限，返回原图");
                let output_data = encode_image(&img, format)?;
                return Ok(ResizeResult {
                    data: output_data,
                    width: orig_width,
                    height: orig_height,
                    format: format!("{:?}", format).to_lowercase(),
                });
            }
            let ratio = max_h as f32 / orig_height as f32;
            let new_w = (orig_width as f32 * ratio).round() as u32;
            console_log!("按高度缩放: ratio={:.3}, 目标尺寸: {}x{}", ratio, new_w, max_h);
            (new_w, max_h)
        }
        (max_w, 0) => {
            // 只限制宽度
            if orig_width <= max_w {
                console_log!("宽度未超限，返回原图");
                let output_data = encode_image(&img, format)?;
                return Ok(ResizeResult {
                    data: output_data,
                    width: orig_width,
                    height: orig_height,
                    format: format!("{:?}", format).to_lowercase(),
                });
            }
            let ratio = max_w as f32 / orig_width as f32;
            let new_h = (orig_height as f32 * ratio).round() as u32;
            console_log!("按宽度缩放: ratio={:.3}, 目标尺寸: {}x{}", ratio, max_w, new_h);
            (max_w, new_h)
        }
        (max_w, max_h) => {
            // 都限制，取较小比例
            if orig_width <= max_w && orig_height <= max_h {
                console_log!("尺寸未超限，返回原图");
                let output_data = encode_image(&img, format)?;
                return Ok(ResizeResult {
                    data: output_data,
                    width: orig_width,
                    height: orig_height,
                    format: format!("{:?}", format).to_lowercase(),
                });
            }
            let width_ratio = max_w as f32 / orig_width as f32;
            let height_ratio = max_h as f32 / orig_height as f32;
            let ratio = width_ratio.min(height_ratio);
            let new_w = (orig_width as f32 * ratio).round() as u32;
            let new_h = (orig_height as f32 * ratio).round() as u32;
            console_log!("按双边限制缩放: ratio={:.3}, 目标尺寸: {}x{}", ratio, new_w, new_h);
            (new_w, new_h)
        }
    };
    
    let algorithm = parse_resize_algorithm(filter)?;
    let resized_img = resize_with_fast_image_resize(&img, new_width, new_height, algorithm)?;
    let output_data = encode_image(&resized_img, format)?;
    
    console_log!("等比例缩放完成，输出大小: {} bytes", output_data.len());
    
    Ok(ResizeResult {
        data: output_data,
        width: new_width,
        height: new_height,
        format: format!("{:?}", format).to_lowercase(),
    })
}

/// 获取图片尺寸信息
#[wasm_bindgen]
pub fn get_image_dimensions(image_data: &[u8]) -> Result<ImageDimensions, String> {
    let (img, _) = decode_image_with_format(image_data)?;
    let (width, height) = img.dimensions();
    
    Ok(ImageDimensions { width, height })
}

/// 获取支持的图片格式列表
#[wasm_bindgen]
pub fn get_supported_formats() -> Vec<String> {
    vec![
        "jpeg".to_string(),
        "jpg".to_string(),
        "png".to_string(),
        "gif".to_string(),
        "webp".to_string(),
        "bmp".to_string(),
        "tiff".to_string(),
        "tif".to_string(),
    ]
}

/// 获取支持的缩放算法列表
#[wasm_bindgen]
pub fn get_supported_algorithms() -> Vec<String> {
    vec![
        "nearest".to_string(),
        "bilinear".to_string(),
        "triangle".to_string(),
        "catmullrom".to_string(),
        "lanczos3".to_string(),
        "gaussian".to_string(),
    ]
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_parse_resize_algorithm() {
        assert!(parse_resize_algorithm("nearest").is_ok());
        assert!(parse_resize_algorithm("bilinear").is_ok());
        assert!(parse_resize_algorithm("triangle").is_ok());
        assert!(parse_resize_algorithm("catmullrom").is_ok());
        assert!(parse_resize_algorithm("lanczos3").is_ok());
        assert!(parse_resize_algorithm("gaussian").is_ok());
        assert!(parse_resize_algorithm("invalid").is_err());
    }

    #[test]
    fn test_aspect_ratio_logic() {
        // 测试等比例缩放的逻辑
        // 这里可以添加更多的单元测试
        // 由于需要实际的图片数据，这些测试可能需要在集成测试中进行
    }
}